"""API Key data models and schemas."""

from typing import Optional, List, Dict, Any
from datetime import datetime
from enum import Enum
from dataclasses import dataclass, field
from bson import ObjectId


class KeyProvider(Enum):
    """Supported API key providers."""
    OPENAI = "openai"
    ANTHROPIC = "anthropic"
    BAIDU = "baidu"
    XUNFEI = "xunfei"
    MOONSHOT = "moonshot"
    ALIBABA = "alibaba"
    DEEPSEEK = "deepseek"
    BYTEDANCE = "bytedance"
    TENCENT = "tencent"
    ZHIPU = "zhipu"


class KeyStatus(Enum):
    """API key status."""
    ACTIVE = "active"
    EXPIRED = "expired"
    REVOKED = "revoked"
    SUSPENDED = "suspended"


class PermissionLevel(Enum):
    """Permission levels for shared keys."""
    READ_ONLY = "read_only"
    USE = "use"
    MANAGE = "manage"


@dataclass
class SharedUser:
    """Shared user information."""
    user_id: str
    permissions: List[str]
    granted_at: datetime = field(default_factory=datetime.utcnow)

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "user_id": self.user_id,
            "permissions": self.permissions,
            "granted_at": self.granted_at.isoformat()
        }


@dataclass
class UsageStats:
    """Usage statistics for API key."""
    total_tokens: int = 0
    total_cost: float = 0.0
    request_count: int = 0
    last_reset: datetime = field(default_factory=datetime.utcnow)

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "total_tokens": self.total_tokens,
            "total_cost": self.total_cost,
            "request_count": self.request_count,
            "last_reset": self.last_reset.isoformat()
        }


@dataclass
class QuotaLimits:
    """Quota limits for API key."""
    daily_tokens: Optional[int] = None
    monthly_tokens: Optional[int] = None
    max_cost: Optional[float] = None
    requests_per_minute: Optional[int] = None
    requests_per_day: Optional[int] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "daily_tokens": self.daily_tokens,
            "monthly_tokens": self.monthly_tokens,
            "max_cost": self.max_cost,
            "requests_per_minute": self.requests_per_minute,
            "requests_per_day": self.requests_per_day
        }


@dataclass
class KeyMetadata:
    """Metadata for API key."""
    validation_status: str = "unvalidated"
    last_validated: Optional[datetime] = None
    supported_models: List[str] = field(default_factory=list)
    validation_error: Optional[str] = None
    response_time_ms: Optional[float] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "validation_status": self.validation_status,
            "last_validated": self.last_validated.isoformat() if self.last_validated else None,
            "supported_models": self.supported_models,
            "validation_error": self.validation_error,
            "response_time_ms": self.response_time_ms
        }


@dataclass
class APIKey:
    """API Key model."""
    _id: Optional[ObjectId] = None
    user_id: str = ""
    provider: KeyProvider = KeyProvider.OPENAI
    key_name: str = ""
    encrypted_key: str = ""
    key_hash: str = ""  # For duplicate detection
    status: KeyStatus = KeyStatus.ACTIVE
    created_at: datetime = field(default_factory=datetime.utcnow)
    last_used_at: Optional[datetime] = None
    expires_at: Optional[datetime] = None
    usage_stats: UsageStats = field(default_factory=UsageStats)
    quota_limits: QuotaLimits = field(default_factory=QuotaLimits)
    shared_with: List[SharedUser] = field(default_factory=list)
    metadata: KeyMetadata = field(default_factory=KeyMetadata)

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for MongoDB storage."""
        doc = {
            "user_id": self.user_id,
            "provider": self.provider.value,
            "key_name": self.key_name,
            "encrypted_key": self.encrypted_key,
            "key_hash": self.key_hash,
            "status": self.status.value,
            "created_at": self.created_at,
            "last_used_at": self.last_used_at,
            "expires_at": self.expires_at,
            "usage_stats": self.usage_stats.to_dict(),
            "quota_limits": self.quota_limits.to_dict(),
            "shared_with": [user.to_dict() for user in self.shared_with],
            "metadata": self.metadata.to_dict()
        }
        
        if self._id:
            doc["_id"] = self._id
            
        return doc

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "APIKey":
        """Create APIKey from dictionary."""
        key = cls()
        
        if "_id" in data:
            key._id = data["_id"]
        
        key.user_id = data.get("user_id", "")
        key.provider = KeyProvider(data.get("provider", "openai"))
        key.key_name = data.get("key_name", "")
        key.encrypted_key = data.get("encrypted_key", "")
        key.key_hash = data.get("key_hash", "")
        key.status = KeyStatus(data.get("status", "active"))
        
        if "created_at" in data:
            key.created_at = data["created_at"]
        if "last_used_at" in data:
            key.last_used_at = data["last_used_at"]
        if "expires_at" in data:
            key.expires_at = data["expires_at"]
            
        # Parse nested structures
        if "usage_stats" in data:
            stats = data["usage_stats"]
            key.usage_stats = UsageStats(
                total_tokens=stats.get("total_tokens", 0),
                total_cost=stats.get("total_cost", 0.0),
                request_count=stats.get("request_count", 0)
            )
            
        if "quota_limits" in data:
            limits = data["quota_limits"]
            key.quota_limits = QuotaLimits(
                daily_tokens=limits.get("daily_tokens"),
                monthly_tokens=limits.get("monthly_tokens"),
                max_cost=limits.get("max_cost"),
                requests_per_minute=limits.get("requests_per_minute"),
                requests_per_day=limits.get("requests_per_day")
            )
            
        if "shared_with" in data:
            key.shared_with = [
                SharedUser(
                    user_id=user["user_id"],
                    permissions=user["permissions"],
                    granted_at=datetime.fromisoformat(user["granted_at"])
                    if isinstance(user.get("granted_at"), str)
                    else user.get("granted_at", datetime.utcnow())
                )
                for user in data["shared_with"]
            ]
            
        if "metadata" in data:
            meta = data["metadata"]
            key.metadata = KeyMetadata(
                validation_status=meta.get("validation_status", "unvalidated"),
                last_validated=datetime.fromisoformat(meta["last_validated"])
                if meta.get("last_validated") else None,
                supported_models=meta.get("supported_models", []),
                validation_error=meta.get("validation_error"),
                response_time_ms=meta.get("response_time_ms")
            )
            
        return key

    def mask_key(self, visible_chars: int = 4) -> str:
        """Return masked version of the key for display."""
        if not self.encrypted_key:
            return ""
        # This is a placeholder - actual key would be decrypted first
        # For now, return a masked pattern
        return f"sk-...{self.key_hash[-visible_chars:]}" if self.key_hash else "sk-..."


@dataclass
class AuditLog:
    """Audit log entry model."""
    _id: Optional[ObjectId] = None
    timestamp: datetime = field(default_factory=datetime.utcnow)
    user_id: str = ""
    action: str = ""  # create, update, delete, view, validate, share
    resource_type: str = "api_key"
    resource_id: Optional[str] = None
    details: Dict[str, Any] = field(default_factory=dict)
    ip_address: Optional[str] = None
    user_agent: Optional[str] = None
    result: str = "success"  # success, failure
    error_message: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for MongoDB storage."""
        doc = {
            "timestamp": self.timestamp,
            "user_id": self.user_id,
            "action": self.action,
            "resource_type": self.resource_type,
            "resource_id": self.resource_id,
            "details": self.details,
            "ip_address": self.ip_address,
            "user_agent": self.user_agent,
            "result": self.result,
            "error_message": self.error_message
        }
        
        if self._id:
            doc["_id"] = self._id
            
        return doc

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "AuditLog":
        """Create AuditLog from dictionary."""
        log = cls()
        
        if "_id" in data:
            log._id = data["_id"]
            
        log.timestamp = data.get("timestamp", datetime.utcnow())
        log.user_id = data.get("user_id", "")
        log.action = data.get("action", "")
        log.resource_type = data.get("resource_type", "api_key")
        log.resource_id = data.get("resource_id")
        log.details = data.get("details", {})
        log.ip_address = data.get("ip_address")
        log.user_agent = data.get("user_agent")
        log.result = data.get("result", "success")
        log.error_message = data.get("error_message")
        
        return log


# MongoDB indexes configuration
INDEXES = [
    # API Keys collection indexes
    {
        "collection": "api_keys",
        "indexes": [
            {"keys": [("user_id", 1)], "name": "idx_user_id"},
            {"keys": [("provider", 1)], "name": "idx_provider"},
            {"keys": [("status", 1)], "name": "idx_status"},
            {"keys": [("key_hash", 1)], "name": "idx_key_hash", "unique": True},
            {"keys": [("created_at", -1)], "name": "idx_created_at"},
            {"keys": [("last_used_at", -1)], "name": "idx_last_used_at"},
            {"keys": [("user_id", 1), ("provider", 1), ("status", 1)], "name": "idx_user_provider_status"},
        ]
    },
    # Audit logs collection indexes
    {
        "collection": "audit_logs",
        "indexes": [
            {"keys": [("timestamp", -1)], "name": "idx_timestamp"},
            {"keys": [("user_id", 1)], "name": "idx_user_id"},
            {"keys": [("action", 1)], "name": "idx_action"},
            {"keys": [("resource_id", 1)], "name": "idx_resource_id"},
            {"keys": [("user_id", 1), ("timestamp", -1)], "name": "idx_user_timestamp"},
            {"keys": [("timestamp", -1)], "name": "idx_ttl", "expireAfterSeconds": 7776000}  # 90 days TTL
        ]
    }
]